using System;
using System.Collections;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;

namespace Trentacular.SharePoint.Util
{
	/// <summary>
	/// Summary description for Util.
	/// </summary>
	public static class StringUtils
    {
        public static bool NullSafeEquals(string str1, string str2)
        {
            return NullSafeEquals(str1, str2, StringComparison.InvariantCulture);
        }

        public static bool NullSafeEquals(string str1, string str2, StringComparison comparisonType)
        {
            if (str1 == null && str2 == null)
                return true;

            if (str1 == null || str2 == null)
                return false;

            return str1.Equals(str2, comparisonType);
        }

        public static string Delimit(this IEnumerable input, string startDelimiter, string endDelimiter)
        {
            StringBuilder sb = new StringBuilder();
            foreach (object s in input)
            {
                sb.Append(startDelimiter).Append(s.ToString()).Append(endDelimiter);
            }
            return sb.ToString();
        }

        public static string Delimit(this IEnumerable input, string delimiter)
        {
            StringBuilder sb = new StringBuilder();

            foreach (object o in input)
            {
                sb.Append(o == null ? "" : o.ToString());
                sb.Append(delimiter);
            }

            if (sb.Length > 0)
            {
                sb.Remove(sb.Length - delimiter.Length, delimiter.Length);
            }

            return sb.ToString();
        }

        public static string ReplaceStrings(this string template, IDictionary values, string formatString)
        {
            for (IDictionaryEnumerator iter = values.GetEnumerator(); iter.MoveNext(); )
            {
                string key = iter.Key.ToString();
                if (formatString != null)
                    key = string.Format(formatString, key);
                string value = null;
                if (iter.Value != null)
                    value = iter.Value.ToString();
                template = template.Replace(key, value);
            }
            return template;
        }

        /// <summary>
        /// Simple template population using IDictionary for keys.
        /// Looks for exact match to Key in template string and replaces with Value.
        /// </summary>
        public static string ReplaceStrings(this string template, IDictionary values)
        {
            return ReplaceStrings(template, values, null);
        }

        public static string Replace(this string input, Regex regex, Converter<Match, string> converter)
        {
            Match match = regex.Match(input);
            if (match.Success)
            {
                StringBuilder sb = new StringBuilder();
                int startIndex = 0;
                while (match.Success)
                {
                    if (match.Index != startIndex)
                        sb.Append(input, startIndex, match.Index - startIndex);
                    startIndex = match.Index + match.Length;
                    // do replace                    
                    sb.Append(converter(match));
                    if (startIndex < input.Length)
                    {
                        sb.Append(input, startIndex, input.Length - startIndex);
                    }
                    match = match.NextMatch();
                }
                return sb.ToString();
            }
            return input;

        }

        public static string ConvertHtmlToPlainText(this string html)
        {
            // First remove linebreaks and tabs
            string result = html.Replace("\r", " ").Replace("\n", " ").Replace("\t", " ");
            
            // Add "real linebreaks" before and after Ps and DIVs
            //result = Regex.Replace(result, @"(<p[^>]*>|</p[^>]*>|<br>|<br\s*/>)", "<br/>", "\n");

            // strip out javascript
            result = Regex.Replace(result, @"<script[^>]*?>.*?</script>", string.Empty, RegexOptions.IgnoreCase);

            // strip out all tags
            result = Regex.Replace(result, @"<[^>]*>", string.Empty, RegexOptions.IgnoreCase);
            // result = Regex.Replace(result, @"<[\/\!]*?[^<>]*?>", string.Empty, RegexOptions.IgnoreCase);

            // replace special characters
            result = Regex.Replace(result, @"&bull;", " * ", RegexOptions.IgnoreCase);
            result = Regex.Replace(result, @"&lsaquo;", "<", RegexOptions.IgnoreCase);
            result = Regex.Replace(result, @"&rsaquo;", ">", RegexOptions.IgnoreCase);
            result = Regex.Replace(result, @"&(rsquo|lsquo);", "'", RegexOptions.IgnoreCase);
            result = Regex.Replace(result, @"&(quot|ldquo|rdquo);", "\"", RegexOptions.IgnoreCase);            
            result = Regex.Replace(result, @"&trade;", "(tm)", RegexOptions.IgnoreCase);
            result = Regex.Replace(result, @"&frasl;", "/", RegexOptions.IgnoreCase);
            result = Regex.Replace(result, @"&(quot|#34|#034|#x22);", "\"", RegexOptions.IgnoreCase);
            result = Regex.Replace(result, @"&(amp|#38|#038|#x26);", "&", RegexOptions.IgnoreCase);
            result = Regex.Replace(result, @"&(lt|#60|#060|#x3c);", "<", RegexOptions.IgnoreCase);
            result = Regex.Replace(result, @"&(gt|#62|#062|#x3e);", ">", RegexOptions.IgnoreCase);
            result = Regex.Replace(result, @"&(copy|#169);", "(c)", RegexOptions.IgnoreCase);
            result = Regex.Replace(result, @"&(reg|#174);", "(r)", RegexOptions.IgnoreCase);

            // Remove all others. More can be added, see
            // http://hotwired.lycos.com/webmonkey/reference/special_characters/
            result = Regex.Replace(result, @"&(.{2,6});", string.Empty, RegexOptions.IgnoreCase);

            // Remove repeating spaces
            result = Regex.Replace(result, @"( )+", " ");
            
            return result;
        }

        public static string ConvertPlainTextToHtml(this string text, bool expandHyperlinks)
        {
            if (text == null)
                return null;

            text = HttpUtility.HtmlEncode(text);

            if (expandHyperlinks)
                text = text.ExpandHyperlinks(string.Empty);

            return text
                .Replace("  ", "&nbsp;&nbsp;")
                .Replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;")
                .Replace(Environment.NewLine, "<br />");
        }

        /// <summary>
        /// this function strips non-numeric values out of a string and returns the numeric content of a string
        /// http://coercedcode.blogspot.com/2008/02/c.html
        /// </summary>
        /// <param name="Value"></param>
        /// <returns></returns>
        public static string StripNonNumeric(this string text)
        {
            if (text == null)
                return null;

            return Regex.Replace(text, "\\D", "");
        }

        public static string TruncateText(this string text, int characters, bool avoidWordBreak, bool addEllipsis)
        {
            if (text == null)
                return null;

            int stringSize = characters;

            if (text.Length <= stringSize)
                return text;

            if (addEllipsis)
                stringSize -= 3;

            stringSize = Math.Max(0, Math.Min(text.Length, stringSize));

            text = text.Substring(0, stringSize);

            if (avoidWordBreak)
            {
                int lastSpaceIndex = text.LastIndexOf(" ");
                if (lastSpaceIndex > 0 && characters - lastSpaceIndex < 10)
                    text = text.Substring(0, text.LastIndexOf(" "));
            }

            if (addEllipsis)
                text += "...";

            return text;
        }

        public static string ExpandHyperlinks(this string text)
        {
            return ExpandHyperlinks(text, null);
        }

        /// <summary>
        /// Expands links into HTML hyperlinks inside of text or HTML.
        /// http://www.west-wind.com/WebLog/posts/9779.aspx
        /// </summary>
        /// <param name="Text">The text to expand</param>
        /// <param name="Target">Target frame where output is displayed</param>
        /// <returns></returns>
        public static string ExpandHyperlinks(this string text, string target)
        {
            if (text == null)
                return null;

            var pattern = @"[""'=]?(http://|ftp://|https://|www\.|ftp\.[\w]+)([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])";
            var targetAttribute = !string.IsNullOrEmpty(target) ? " target='" + target + "'" : "";

            // Expand embedded hyperlinks
            var options = RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline | RegexOptions.IgnoreCase;

            var reg = new Regex(pattern, options);
            var matchEval = new MatchEvaluator(delegate(Match match)
            {
                string href = match.Value; // M.Groups[0].Value;

                // *** if string starts within an HREF don't expand it
                if (href.StartsWith("=") ||
                    href.StartsWith("'") ||
                    href.StartsWith("\""))
                    return href;

                string displayText = href;

                if (href.IndexOf("://") < 0)
                {
                    if (href.StartsWith("www."))
                        href = "http://" + href;
                    else if (href.StartsWith("ftp"))
                        href = "ftp://" + href;
                    else if (href.IndexOf("@") > -1)
                        href = "mailto:" + href;
                }

                return string.Format("<a href='{0}'{1}>{2}</a>", href, targetAttribute, displayText);
            });

            return Regex.Replace(text, pattern, matchEval);
        }
	}
}
